<template>
  <div class="editable-text-container">
    <div
      ref="editableText"
      :class="[
        'editable-text',
        { readonly: readonly }
      ]"
      :contenteditable="!readonly"
      @input="handleInput"
      @compositionstart="handleCompositionStart"
      @compositionend="handleCompositionEnd"
      @blur="handleBlur"
      @keydown="handleKeydown"
      :data-placeholder="placeholder"
    ></div>

    <!-- 代码提示框 -->
    <div
      v-if="showSuggestions && suggestions.length > 0"
      class="suggestion-box"
      :style="suggestionStyle"
    >
      <div
        v-for="(suggestion, index) in suggestions"
        :key="suggestion.atom_key"
        class="suggestion-item"
        :data-type="suggestion.atom_key.charAt(0)"
        @click="selectSuggestion(suggestion)"
        @mouseenter="highlightSuggestion(index)"
        :class="{ highlighted: highlightedIndex === index }"
      >
        <span class="suggestion-text">
          <span class="atom-key">{{ suggestion.atom_key }}</span>
          <span class="atom-name">({{ suggestion.atom_name }})</span>
        </span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'EditableText',
  props: {
    modelValue: {
      type: String,
      default: ''
    },
    readonly: {
      type: Boolean,
      default: false
    },
    options: {
      type: Array,
      default: () => []
    },
    atoms: {
      type: Array,
      default: () => []
    },
    placeholder: {
      type: String,
      default: ''
    }
  },
  emits: ['update:modelValue', 'input', 'change', 'blur', 'focus', 'suggestion-select'],
  data() {
    return {
      isComposing: false,
      showSuggestions: false,
      suggestions: [],
      suggestionPosition: { top: 0, left: 0 },
      highlightedIndex: -1,
      editableElement: null
    };
  },
  computed: {
    suggestionStyle() {
      return {
        position: 'fixed',
        top: this.suggestionPosition.top + 'px',
        left: this.suggestionPosition.left + 'px',
        zIndex: 9999
      };
    }
  },
  watch: {
    modelValue: {
      handler(newValue) {
        if (this.editableElement && this.editableElement.innerText !== newValue) {
          this.editableElement.innerText = newValue || '';
          this.$nextTick(() => {
            this.highlightOptions();
          });
        }
      },
      immediate: true
    }
  },
  mounted() {
    this.initElement();
    document.addEventListener('click', this.handleGlobalClick);
    this.$nextTick(() => {
      if (this.modelValue) {
        this.editableElement.innerText = this.modelValue;
        this.highlightOptions();
      }
    });
  },
  beforeUnmount() {
    this.cleanup();
  },
  methods: {
    initElement() {
      this.editableElement = this.$refs.editableText;
      if (!this.editableElement) {
        this.$nextTick(() => {
          this.editableElement = this.$refs.editableText;
        });
      }
    },

    cleanup() {
      document.removeEventListener('click', this.handleGlobalClick);
    },

    handleInput(event) {
      if (this.isComposing) return;

      const newValue = event.target.innerText || '';
      this.$emit('update:modelValue', newValue);
      this.$emit('input', newValue);

      this.$nextTick(() => {
        this.highlightOptions();
        this.checkSuggestions(event.target);
      });
    },

    handleCompositionStart() {
      this.isComposing = true;
    },

    handleCompositionEnd(event) {
      this.isComposing = false;
      this.$nextTick(() => {
        this.highlightOptions();
        this.checkSuggestions(event.target);
      });
    },

    handleBlur(event) {
      const newValue = event.target.innerText || '';
      this.$emit('change', newValue);
      this.$emit('blur', newValue);

      setTimeout(() => {
        this.showSuggestions = false;
      }, 200);
    },

    handleKeydown(event) {
      if (this.showSuggestions) {
        switch (event.key) {
          case 'ArrowDown':
            event.preventDefault();
            this.navigateSuggestions(1);
            break;
          case 'ArrowUp':
            event.preventDefault();
            this.navigateSuggestions(-1);
            break;
          case 'Enter':
            event.preventDefault();
            if (this.highlightedIndex >= 0) {
              this.selectSuggestion(this.suggestions[this.highlightedIndex]);
            } else {
              event.target.blur();
            }
            break;
          case 'Escape':
            this.showSuggestions = false;
            this.highlightedIndex = -1;
            break;
        }
      } else {
        if (event.key === 'Enter') {
          event.preventDefault();
          event.target.blur();
        }
      }
    },

    navigateSuggestions(direction) {
      const maxIndex = this.suggestions.length - 1;
      let newIndex = this.highlightedIndex + direction;

      if (newIndex < 0) {
        newIndex = maxIndex;
      } else if (newIndex > maxIndex) {
        newIndex = 0;
      }

      this.highlightedIndex = newIndex;
    },

    highlightSuggestion(index) {
      this.highlightedIndex = index;
    },

    checkSuggestions(element) {
      if (!element) return;
      
      const text = element.innerText || '';
      const selection = window.getSelection();

      if (selection.rangeCount === 0) {
        this.showSuggestions = false;
        return;
      }

      const range = selection.getRangeAt(0);
      const cursorOffset = this.getTextOffset(element, range.startContainer, range.startOffset);

      const textBeforeCursor = text.substring(0, cursorOffset);

      const lastSpaceIndex = Math.max(
        textBeforeCursor.lastIndexOf(' '),
        textBeforeCursor.lastIndexOf('+'),
        textBeforeCursor.lastIndexOf('-'),
        textBeforeCursor.lastIndexOf('*'),
        textBeforeCursor.lastIndexOf('/'),
        textBeforeCursor.lastIndexOf('('),
        textBeforeCursor.lastIndexOf(')')
      );

      const currentWord = textBeforeCursor.substring(lastSpaceIndex + 1);

      if (currentWord.length > 0) {
        this.suggestions = this.atoms.filter(atom =>
          atom.atom_key.toLowerCase().startsWith(currentWord.toLowerCase())
        );

        if (this.suggestions.length > 0) {
          this.showSuggestions = true;
          this.highlightedIndex = 0;
          this.updateSuggestionPosition(element, range);
        } else {
          this.showSuggestions = false;
        }
      } else {
        this.showSuggestions = false;
      }
    },

    updateSuggestionPosition(element, range) {
      try {
        const tempRange = range.cloneRange();
        tempRange.collapse(true);
        const rect = tempRange.getBoundingClientRect();

        this.suggestionPosition = {
          top: rect.bottom + window.scrollY + 5,
          left: rect.left + window.scrollX
        };
      } catch (error) {
        const elementRect = element.getBoundingClientRect();
        this.suggestionPosition = {
          top: elementRect.bottom + window.scrollY + 5,
          left: elementRect.left + window.scrollX
        };
      }
    },

    handleGlobalClick(event) {
      if (!this.editableElement) return;
      
      const suggestionBox = document.querySelector('.suggestion-box');
      const editableText = this.editableElement;
      
      if (suggestionBox && !suggestionBox.contains(event.target) && 
          editableText && !editableText.contains(event.target)) {
        this.showSuggestions = false;
        this.highlightedIndex = -1;
      }
    },

    highlightOptions() {
      if (!this.editableElement || this.readonly) return;

      const text = this.editableElement.textContent || '';
      let highlightedText = text;

      // 为每个选项添加高亮标签，使用固定的 'highlight-option' 类名
      this.options.forEach(option => {
        if (option && option.trim()) {
          const regex = new RegExp(`(${this.escapeRegex(option)})`, 'g');
          const replacement = `<span class="highlight-option">$1</span>`;
          highlightedText = highlightedText.replace(regex, replacement);
        }
      });

      // 保存当前光标位置
      const selection = window.getSelection();
      const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
      let cursorOffset = 0;

      if (range && range.startContainer === this.editableElement) {
        cursorOffset = range.startOffset;
      } else if (range && this.editableElement.contains(range.startContainer)) {
        cursorOffset = this.getTextOffset(this.editableElement, range.startContainer, range.startOffset);
      }

      // 更新内容
      this.editableElement.innerHTML = highlightedText;

      // 恢复光标位置
      this.restoreCursorPosition(cursorOffset);
    },

    selectSuggestion(suggestion) {
      if (!this.editableElement) return;
      
      const selection = window.getSelection();
      if (selection.rangeCount === 0) return;

      const range = selection.getRangeAt(0);
      const text = this.editableElement.innerText || '';
      const cursorOffset = this.getTextOffset(this.editableElement, range.startContainer, range.startOffset);

      const textBeforeCursor = text.substring(0, cursorOffset);

      const lastSpaceIndex = Math.max(
        textBeforeCursor.lastIndexOf(' '),
        textBeforeCursor.lastIndexOf('+'),
        textBeforeCursor.lastIndexOf('-'),
        textBeforeCursor.lastIndexOf('*'),
        textBeforeCursor.lastIndexOf('/'),
        textBeforeCursor.lastIndexOf('('),
        textBeforeCursor.lastIndexOf(')')
      );

      const currentWord = textBeforeCursor.substring(lastSpaceIndex + 1);
      const textAfterCursor = text.substring(cursorOffset);

      const newText = textBeforeCursor.substring(0, lastSpaceIndex + 1) +
                     suggestion.atom_key +
                     textAfterCursor;

      this.editableElement.innerText = newText;
      this.$emit('update:modelValue', newText);

      const newCursorOffset = lastSpaceIndex + 1 + suggestion.atom_key.length;
      this.setCursorAtOffset(newCursorOffset);

      this.$nextTick(() => {
        this.highlightOptions();
        this.$emit('suggestion-select', suggestion, newText);
      });

      this.showSuggestions = false;
      this.highlightedIndex = -1;
    },

    escapeRegex(string) {
      return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    },

    getTextOffset(element, node, offset) {
      let textOffset = 0;
      const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);

      let currentNode;
      while ((currentNode = walker.nextNode())) {
        if (currentNode === node) {
          return textOffset + offset;
        }
        textOffset += currentNode.textContent.length;
      }
      return textOffset;
    },

    restoreCursorPosition(offset) {
      if (!this.editableElement) return;
      
      const range = document.createRange();
      const selection = window.getSelection();

      try {
        const textNode = this.getTextNodeAtOffset(this.editableElement, offset);
        if (textNode) {
          const nodeOffset = Math.min(offset, textNode.textContent.length);
          range.setStart(textNode, nodeOffset);
          range.collapse(true);
          selection.removeAllRanges();
          selection.addRange(range);
        } else {
          this.setCursorToEnd();
        }
      } catch {
        this.setCursorToEnd();
      }
    },

    getTextNodeAtOffset(element, offset) {
      const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);

      let currentOffset = 0;
      let currentNode;
      while ((currentNode = walker.nextNode())) {
        const nodeLength = currentNode.textContent.length;
        if (currentOffset + nodeLength >= offset) {
          return currentNode;
        }
        currentOffset += nodeLength;
      }
      return null;
    },

    setCursorAtOffset(offset) {
      if (!this.editableElement) return;
      
      const range = document.createRange();
      const selection = window.getSelection();

      try {
        const textNode = this.getTextNodeAtOffset(this.editableElement, offset);
        if (textNode) {
          const nodeOffset = Math.min(offset, textNode.textContent.length);
          range.setStart(textNode, nodeOffset);
          range.collapse(true);
          selection.removeAllRanges();
          selection.addRange(range);
        } else {
          this.setCursorToEnd();
        }
      } catch (error) {
        this.setCursorToEnd();
      }
    },

    setCursorToEnd() {
      if (!this.editableElement) return;
      
      const range = document.createRange();
      const selection = window.getSelection();
      range.selectNodeContents(this.editableElement);
      range.collapse(false);
      selection.removeAllRanges();
      selection.addRange(range);
    },

    getValue() {
      return this.editableElement ? this.editableElement.innerText || '' : '';
    },

    setValue(value) {
      if (this.editableElement) {
        this.editableElement.innerText = value || '';
        this.$nextTick(() => {
          this.highlightOptions();
        });
      }
    },

    focus() {
      if (this.editableElement) {
        this.editableElement.focus();
        this.setCursorToEnd();
      }
    }
  }
};
</script>

<style>
/* 全局样式，确保高亮样式生效 */
.editable-text-container {
  position: relative;
  display: inline-block;
  width: 100%;
}

.editable-text {
  display: inline-block;
  width: 100%;
  min-height: 64px;
  border: 1px solid #dcdfe6;
  border-radius: 3px;
  padding: 5px 11px;
  line-height: 21px;
  outline: none;
  word-wrap: break-word;
  white-space: pre-wrap;
}

.editable-text.readonly {
  background-color: #f5f7fa;
  cursor: default;
}

.editable-text:focus {
  border-color: #409eff;
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}

.editable-text:empty::before {
  content: attr(data-placeholder);
  color: #c0c4cc;
  pointer-events: none;
}

.highlight-option {
  background-color: #e6f7ff;
  color: #1890ff;
  border-radius: 4px;
  padding: 2px 6px;
  margin: 0 2px;
  display: inline-block;
  font-weight: 500;
}

/* 代码提示框样式 */
.suggestion-box {
  background: #f8f9fa;
  border: 1px solid #e1e4e8;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  max-height: 300px;
  overflow-y: auto;
  min-width: 200px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
  font-size: 13px;
  line-height: 1.4;
  position: fixed;
  z-index: 9999;
}

.suggestion-item {
  padding: 6px 12px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #e1e4e8;
  position: relative;
  cursor: pointer;
}

.suggestion-item:last-child {
  border-bottom: none;
}

.suggestion-item:hover,
.suggestion-item.highlighted {
  background-color: #e3f2fd;
}

/* 选项文本样式 */
.suggestion-text {
  flex: 1;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  color: #24292e;
}

/* atom_key 样式 - 重点突出 */
.atom-key {
  font-weight: 600;
  color: #007acc;
  background-color: #e3f2fd;
  padding: 1px 4px;
  border-radius: 2px;
}

/* atom_name 样式 */
.atom-name {
  color: #666;
  font-weight: 400;
  margin-left: 2px;
}

/* 滚动条样式 */
.suggestion-box::-webkit-scrollbar {
  width: 6px;
}

.suggestion-box::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.suggestion-box::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.suggestion-box::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}
</style> 